package top.cardone.security.shiro.realm.impl;

import lombok.Getter;
import lombok.Setter;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import top.cardone.context.ApplicationContextHolder;
import top.cardone.core.CodeException;
import top.cardone.core.util.func.Func1;
import top.cardone.security.shiro.authc.impl.StatelessTokenImpl;

import java.util.Set;

/**
 * Created by yht on 16-2-2.
 */
@Log4j2
public class StatelessRealmImpl extends AuthorizingRealm {
    @Setter
    @Getter
    private String readListRoleFuncName = StringUtils.EMPTY;

    @Setter
    @Getter
    private String readListPermissionFuncName = StringUtils.EMPTY;

    @Setter
    @Getter
    private String readCredentialsFuncName = StringUtils.EMPTY;

    @Override
    public boolean supports(AuthenticationToken token) {
        //仅支持 StatelessTokenImpl 类型的Token
        return token instanceof StatelessTokenImpl;
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        //根据用户名查找角色，请根据需求实现
        String username = (String) principals.getPrimaryPrincipal();

        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();

        if (StringUtils.isNotBlank(readListRoleFuncName)) {
            authorizationInfo.setRoles((Set<String>) ApplicationContextHolder.func(Func1.class, func -> func.func(username), readListRoleFuncName));
        }

        if (StringUtils.isNotBlank(readListPermissionFuncName)) {
            authorizationInfo.setStringPermissions((Set<String>) ApplicationContextHolder.func(Func1.class, func -> func.func(username), readListPermissionFuncName));
        }

        return authorizationInfo;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        StatelessTokenImpl statelessToken = (StatelessTokenImpl) token;

        if (statelessToken.getCredentials() == null || StringUtils.isBlank(statelessToken.getCredentials().toString())) {
            throw new CodeException("000100", "凭证不能为空值!");
        }

        if (statelessToken.getPrincipal() == null || StringUtils.isBlank(statelessToken.getPrincipal().toString())) {
            throw new CodeException("000100", "用户编号不能为空值!");
        }

        String credentials = null;

        if (StringUtils.isNotBlank(readCredentialsFuncName)) {
            credentials = (String) ApplicationContextHolder.func(Func1.class, func -> func.func(statelessToken.getPrincipal()), readCredentialsFuncName);
        }

        //然后进行客户端消息摘要和服务器端消息摘要的匹配
        return new SimpleAuthenticationInfo(statelessToken.getPrincipal(), credentials, getName());
    }
}